package com.example.opengl.avengine;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;

import java.io.IOException;
import java.nio.ByteBuffer;

import static android.media.MediaCodec.BUFFER_FLAG_END_OF_STREAM;

/**
 * 音频片段
 */
public class AVAudio extends AVComponent {

    public static final String TAG = AVComponent.class.getSimpleName();
    //输入结束标识
    private boolean isInputEOF;
    //输出结束标识
    private boolean isOutputEOF;
    //视频路径
    private String path;
    //解码器
    private MediaCodec mediaCodec;
    //媒体提取器
    private MediaExtractor mediaExtractor;
    //媒体格式
    private MediaFormat mediaFormat;
    //数据流
    private ByteBuffer sampleBuffer;
   public AudioTrack audioTrack;
   public   int audioInputBufferSize;

    public AVAudio(long engineStartTime, String path) {
        super(engineStartTime, AVComponentType.AUDIO);
        this.path = path;
    }

    @Override
    public int open() {
        if (isOpen()) return RESULT_FAILED;
        isOutputEOF = false;
        isInputEOF = false;
        mediaExtractor = new MediaExtractor();
        try {
            mediaExtractor.setDataSource(path);
            for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
                if (mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME).contains("audio")) {
                    mediaFormat = mediaExtractor.getTrackFormat(i);
                    mediaExtractor.selectTrack(i);
                    long duration = mediaFormat.getLong(MediaFormat.KEY_DURATION);
                    //设置切割起始时间
                    setClipStartTime(0);
                    setClipEndTime(duration);
                    setDuration(duration);
                    mediaCodec = MediaCodec.createDecoderByType(mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME));
                    //帧率
                    int sampleRate  = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                    Log.i(TAG, "opensampleRate: sampleRate:"+sampleRate);
                    break;
                }
            }
            if (mediaCodec == null) {
                return RESULT_FAILED;
            }
            mediaCodec.configure(mediaFormat, null, null, 0);
            mediaCodec.start();
            sampleBuffer = ByteBuffer.allocateDirect(mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE));
            Log.i(TAG, "opensfd: sampleBuffer:"+sampleBuffer);
            //获取音频采样率
            int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
            //获取音频声道数
            int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
            //计算缓冲区大小
            int bufferSize = AudioTrack.getMinBufferSize(
                    sampleRate,channelCount == 1?AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT
        );

            int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);

             audioInputBufferSize =  bufferSize > 0? bufferSize * 4 : maxInputSize;

            int frameSizeInBytes = channelCount * 2 ;

            audioInputBufferSize = (audioInputBufferSize / frameSizeInBytes) * frameSizeInBytes;

            Log.i("TAG147d", "initMediaCodec: path:"+path);
            sampleBuffer = ByteBuffer.allocateDirect(maxInputSize);
            audioTrack = new AudioTrack(
                    AudioManager.STREAM_MUSIC,
                    sampleRate,
            channelCount == 1? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    audioInputBufferSize,
                    AudioTrack.MODE_STREAM
        );

            audioTrack.play();



            //设置数据流缓存
            peekFrame().setByteBuffer(ByteBuffer.allocateDirect(4096));//TODO
            //设置视频区间时长
            setEngineEndTime(getEngineStartTime() + getDuration());
            //标识开始
            markOpen(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return RESULT_OK;
    }

    @Override
    public int close() {
        if (!isOpen()) return RESULT_FAILED;
        try {
            if (mediaCodec != null) {
                mediaCodec.stop();
                mediaCodec.release();
                mediaCodec = null;
            }
            if (mediaExtractor != null) {
                mediaExtractor.release();
                mediaExtractor = null;
            }
        } catch (Exception e) {
        }
        if (sampleBuffer != null) {
            sampleBuffer = null;
        }
        isInputEOF = false;
        isOutputEOF = false;
        markOpen(false);
        return RESULT_OK;
    }

    @Override
    public int readFrame() {//没打开或者已经返回一个eof frame,那么就返回RESULT_FAILED
        if (!isOpen() || isOutputEOF) return RESULT_FAILED;
        //获取一帧数据
        AVFrame avFrame = peekFrame();
        //如果输入和输出没有结束
        while (!isInputEOF || !isOutputEOF) {
            try {
                //输入未结束
                if (!isInputEOF) {
                    //有效数据下标
                    int inputBufIdx = mediaCodec.dequeueInputBuffer(0);
                    if (inputBufIdx >= 0) {
                        int sampleSize = mediaExtractor.readSampleData(sampleBuffer, 0);
                        if (sampleSize < 0) {
                            sampleSize = 0;
                            //数据读取结束
                            isInputEOF = true;
                        }
                        mediaCodec.getInputBuffer(inputBufIdx).put(sampleBuffer);
                        mediaCodec.queueInputBuffer(inputBufIdx, 0,
                                sampleSize,
                                mediaExtractor.getSampleTime(),
                                isInputEOF ? BUFFER_FLAG_END_OF_STREAM : 0);
                        //获取下一帧数据
                        mediaExtractor.advance();
                    }
                }
                //输出未结束
                if (!isOutputEOF) {
                    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                    int outputBufIdx = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
                    if (outputBufIdx >= 0) {
                        if (bufferInfo.flags == BUFFER_FLAG_END_OF_STREAM) {
                            isOutputEOF = true;
                            //输出结束
                            avFrame.setPts(getClipDuration() + getEngineStartTime());//换算Engine的时间
                            avFrame.setEof(true);
                        } else {
                            avFrame.setEof(false);
                            avFrame.setPts(bufferInfo.presentationTimeUs - getClipStartTime() + getEngineStartTime());//换算Engine的时间
                        }
                        ByteBuffer byteBuffer = mediaCodec.getOutputBuffer(outputBufIdx);
                        peekFrame().getByteBuffer().position(0);
                        peekFrame().getByteBuffer().put(byteBuffer);
                        peekFrame().getByteBuffer().position(0);
                        peekFrame().setDuration(9089);//TODO
                        byteBuffer.position(0);
                        avFrame.setValid(true);
                        byte[] chunk =new byte[bufferInfo.size];
                        byteBuffer.get(chunk);
                        byteBuffer.clear();
                        audioTrack.write(chunk, 0, chunk.length);
                        mediaCodec.releaseOutputBuffer(outputBufIdx, false);
                        break;
                    } else if (outputBufIdx == MediaCodec.INFO_TRY_AGAIN_LATER) {
                    } else if (outputBufIdx == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                    } else if (outputBufIdx == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    }
                }
            } catch (Exception e) {
                retry(peekFrame().getPts() - getEngineStartTime() + getClipStartTime());
                return RESULT_FAILED;
            }
        }
        avFrame.setEof(isOutputEOF);
        return RESULT_OK;
    }
    //seekTo关键帧
    @Override
    public int seekFrame(long position) {
        if (!isOpen()) return RESULT_FAILED;
        long correctPosition = position - getEngineStartTime();
        if (position < getEngineStartTime() || position > getEngineEndTime() || correctPosition > getDuration()) {
            return RESULT_FAILED;
        }
        isInputEOF = false;
        isOutputEOF = false;
        if (position < getPosition()) {
            mediaExtractor.seekTo(correctPosition + getClipStartTime(), MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
            mediaCodec.flush();
            peekFrame().setPts(Long.MIN_VALUE);
        }
        while (peekFrame().getPts() < position) {
            readFrame();
        }
        setPosition(position);
        return RESULT_OK;
    }

    private void retry(long position) {
        close();
        open();
        seekFrame(position);
    }

    @Override
    public String toString() {
        return "AVAudio{\n" +
                "\tisInputEOF=" + isInputEOF + "\n" +
                "\tisOutputEOF=" + isOutputEOF + "\n" +
                "\tpath='" + path + '\'' + "\n" +
                "\tmediaCodec=" + mediaCodec + "\n" +
                "\tmediaExtractor=" + mediaExtractor + "\n" +
                "\tmediaFormat=" + mediaFormat + "\n" +
                "\tsampleBuffer=" + sampleBuffer + "\n" +
                "} " + super.toString() + "\n";
    }
}
